﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using GBPVRX2.UiSupport;
using GBPVR.Public;
using System.Drawing;
using System.Xml;
using GBPVRX2;
using System.Collections;
using GBPVRLibrary.UtilityLibrary;

namespace GBPVRLibrary.ControlLibrary
{
    public class TextArea:GuiElement
    {
        private GBPVRUiElementNonAnimating Texture { get; set; }

        /// <summary>
        /// The amount the textarea will scroll each time it is moved
        /// </summary>
        private float ScrollAmount { get; set; }
        /// <summary>
        /// The starting bottom point of y 
        /// </summary>
        private float StartPointY { get; set; }
        /// <summary>
        /// The text used in the current texture
        /// </summary>
        private string TextureText { get; set; }

        private float YTop, YBottom;
        

        /// <summary>
        /// the width of the scrollbar
        /// </summary>
        private int ScrollBarWidth { get; set; }

        private GBPVRUiElementNonAnimating ScrollBarTop, ScrollBarMiddle, ScrollBarBottom;
        private SizeF ScrollBarTopSize, ScrollBarMiddleSize, ScrollBarBottomSize;

        /// <summary>
        /// Constructs a TextArea
        /// </summary>
        /// <param name="SkinHelper">the SkinHelper the placement node comes from, usually the plugins skin helper</param>
        /// <param name="PlacementNode">the placement node of the textarea</param>
        public TextArea(SkinHelper2 SkinHelper, XmlNode PlacementNode)
        {
            Font = new SkinFont() 
                   { 
                       Brush = SkinHelper.getNamedFontBrush(PlacementNode.Attributes["textStyle"].Value), 
                       Font = SkinHelper.getNamedFont(PlacementNode.Attributes["textStyle"].Value),
                       BorderColor = PlacementNode.Attributes["borderColor"] == null ? Color.Transparent : SkinHelper.getNamedColor(PlacementNode.Attributes["borderColor"].Value),
                       OutlineWidth = PlacementNode.Attributes["outlineWidth"] == null ? 0 : int.Parse(PlacementNode.Attributes["outlineWidth"].Value)
                   };     
            
            this.Location = SkinHelper.getPlacementRect(PlacementNode.Attributes["name"].Value);

            ScrollBarTop = new GBPVRUiElementNonAnimating(String.Format("{0}ScrollBarTop", this.GetType().Name), new RectangleF(), GuiElement.SkinHelper.getNamedImage("ScrollBar-Top", new Hashtable()));
            ScrollBarTopSize = GuiElement.SkinHelper.getNamedImageRelativeSize("ScrollBar-Top");
            ScrollBarMiddle = new GBPVRUiElementNonAnimating(String.Format("{0}ScrollBarTop", this.GetType().Name), new RectangleF(), GuiElement.SkinHelper.getNamedImage("ScrollBar-Middle", new Hashtable()));
            ScrollBarMiddleSize = GuiElement.SkinHelper.getNamedImageRelativeSize("ScrollBar-Middle");
            ScrollBarBottom = new GBPVRUiElementNonAnimating(String.Format("{0}ScrollBarTop", this.GetType().Name), new RectangleF(), GuiElement.SkinHelper.getNamedImage("ScrollBar-Bottom", new Hashtable()));
            ScrollBarBottomSize = GuiElement.SkinHelper.getNamedImageRelativeSize("ScrollBar-Bottom");

            ScrollBarWidth = GuiElement.SkinHelper.getNamedImagePixelSize("ScrollBar-Middle").Width;
        }

        private string _Text;
        /// <summary>
        /// Gets or sets the text to be displayed in the TextArea
        /// </summary>
        public string Text
        {
            get { return _Text; }
            set
            {
                if ((value != _Text || Texture == null) && !String.IsNullOrEmpty(value))
                {

                    SizeInPixels = new Size
                                   (
                                        (int)(this.Location.Width * SkinHelper.getCurrentScreenSize().Width / 100) - (ScrollBarWidth + 10),
                                        (int)(this.Location.Height * SkinHelper.getCurrentScreenSize().Height / 100)
                                   );
                    SizeF size = Font.MeasureString(value, SizeInPixels.Width);
                    float LineHeight = Font.MeasureString("ABCDEFGHIJKLMNOPRSTUVWXYZabcdefghijklmnoprstuvwxyz", 1000).Height;
                    float Lines = size.Height / LineHeight;

                    // render the text to a Image
                    Image img = new Bitmap(SizeInPixels.Width, (int)size.Height + 1);
                    Font.Render(img, new Rectangle(0, 0, SizeInPixels.Width, (int)Math.Round(size.Height + 0.5)), value);
                    if (Texture != null)
                        PluginHelper.DisposeResource(Texture);
                    Texture = new GBPVRUiElementNonAnimating("TextArea", Location, img);

                    // get how many lines will fit
                    float LinesDisplayable = SizeInPixels.Height / LineHeight;
                    this.PercentDisplayable = SizeInPixels.Height / size.Height;
                    YTop = 0;
                    if (size.Height < SizeInPixels.Height)
                    {
                        ScrollAmount = 0f;
                        StartPointY = 1f * PercentDisplayable;
                        
                        Texture.textureBottomLeft.Y = StartPointY;
                        Texture.textureBottomRight.Y = StartPointY;
                    }
                    else
                    {
                        ScrollAmount = 1 / Lines;
                        StartPointY = 1f * PercentDisplayable;                        
                        Texture.textureBottomLeft.Y = StartPointY;
                        Texture.textureBottomRight.Y = StartPointY;
                        SetScrollBar();
                    }

                    YBottom = StartPointY;

                    TextureText = value;
                }
                _Text = value;
            }
        }

        /// <summary>
        /// The size in pixels the textarea takes up
        /// </summary>
        private Size SizeInPixels { get; set; }

        /// <summary>
        /// The skinfont the textarea will use to render
        /// </summary>
        public SkinFont Font { get; set; }

        /// <summary>
        /// The percent of the total text displayable in the textareas bounds
        /// </summary>
        private float PercentDisplayable { get; set; }

        protected override void Render(System.Collections.ArrayList RenderList, ref bool RequiresMoreRendering)
        {
            if (String.IsNullOrEmpty(Text))
                return;

            RenderList.Add(Texture);

            if (ScrollAmount > 0)
            {
                RenderList.Add(ScrollBarMiddle);
                RenderList.Add(ScrollBarTop);
                RenderList.Add(ScrollBarBottom);
            }            
        }

        protected override void PostRender(ArrayList RenderList)
        {
            Texture.textureBottomLeft.Y = YBottom;
            Texture.textureBottomRight.Y = YBottom;
            Texture.textureTopLeft.Y = YTop;
            Texture.textureTopRight.Y = YTop;
        }

        /// <summary>
        /// Scrolls the textarea down
        /// </summary>
        public void ScrollDown()
        {
            if (ScrollAmount == 0)
                return;
            YBottom += ScrollAmount;
            YTop += ScrollAmount;
            Texture.textureTopLeft.Y += ScrollAmount;
            Texture.textureTopRight.Y += ScrollAmount;
            Texture.textureBottomLeft.Y += ScrollAmount;
            Texture.textureBottomRight.Y += ScrollAmount;
            if (Texture.textureBottomLeft.Y > 1f)
            {
                float diff = Texture.textureBottomLeft.Y - 1f;
                Texture.textureTopLeft.Y -= diff;
                Texture.textureTopRight.Y -= diff;
                Texture.textureBottomLeft.Y -= diff;
                Texture.textureBottomRight.Y -= diff;

                YBottom -= diff;
                YTop -= diff;
            }
            SetScrollBar();
        }

        /// <summary>
        /// Scrolls the textarea up
        /// </summary>
        public void ScrollUp()
        {
            if (ScrollAmount == 0)
                return;
            YBottom -= ScrollAmount;
            YTop -= ScrollAmount;

            Texture.textureTopLeft.Y -= ScrollAmount;
            Texture.textureTopRight.Y -= ScrollAmount;
            Texture.textureBottomLeft.Y -= ScrollAmount;
            Texture.textureBottomRight.Y -= ScrollAmount;
            if (Texture.textureTopLeft.Y < 0)
            {
                float diff = Texture.textureTopLeft.Y;
                Texture.textureTopLeft.Y -= diff;
                Texture.textureTopRight.Y -= diff;
                Texture.textureBottomLeft.Y -= diff;
                Texture.textureBottomRight.Y -= diff;

                YBottom -= diff;
                YTop -= diff;
            }
            SetScrollBar();
        }

        /// <summary>
        /// Sets the scroll bars location
        /// </summary>
        private void SetScrollBar()
        {
            float scrollsize = 1 - StartPointY;
            float start = ((Texture.textureBottomLeft.Y - StartPointY) / scrollsize);

            float height = PercentDisplayable * Texture.rect.Height;
            float middleHeight = height - (this.ScrollBarTopSize.Height + this.ScrollBarBottomSize.Height);

            ScrollBarTop.SetRectangle(new RectangleF(this.Texture.rect.Right,
                                                this.Texture.rect.Location.Y + start * (this.Texture.rect.Height - height),
                                                this.ScrollBarTopSize.Width, this.ScrollBarTopSize.Height));

            ScrollBarMiddle.SetRectangle(new RectangleF(this.Texture.rect.Right,
                                                   ScrollBarTop.rect.Bottom,
                                                   this.ScrollBarBottomSize.Width, middleHeight > 0 ? middleHeight : 0));

            ScrollBarBottom.SetRectangle(new RectangleF(this.Texture.rect.Right,
                                                   ScrollBarMiddle.rect.Bottom,
                                                   this.ScrollBarTopSize.Width, this.ScrollBarTopSize.Height));
        }

        public override void Dispose()
        {
            if (Texture != null)
            {
                PluginHelper.DisposeResource(Texture);
                Texture = null;
            }
            if(ScrollBarTop != null)
            {
                PluginHelper.DisposeResource(ScrollBarTop);
                ScrollBarTop = null;
            }
            if(ScrollBarMiddle != null)
            {
                PluginHelper.DisposeResource(ScrollBarMiddle);
                ScrollBarMiddle = null;
            }
            if(ScrollBarBottom != null)
            {
                PluginHelper.DisposeResource(ScrollBarBottom);
                ScrollBarBottom = null;
            }
        }
    }
}
